package me.zzp.configuration;

import feign.Feign;
import feign.gson.GsonDecoder;
import feign.gson.GsonEncoder;
import feign.okhttp.OkHttpClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;

import java.io.IOException;

/**
 * @author zhangzepeng
 */
@Slf4j
@Configuration
@ConditionalOnClass({GsonDecoder.class, GsonEncoder.class})
public class SkeletonConfiguration implements BeanFactoryPostProcessor {

    private <T> T getSkeleton(String prefix, Class<T> type) {
        Feign.Builder feignBuilder = Feign.builder()
                .client(new OkHttpClient())
                .decoder(new GsonDecoder())
                .encoder(new GsonEncoder());
        return feignBuilder.target(type, prefix);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException {
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resolver);
        try {
            for (Resource resource : resolver.getResources("classpath:me/zzp/skeleton/*.class")) {
                if (!resource.isReadable()) {
                    continue;
                }

                MetadataReader reader = metadataReaderFactory.getMetadataReader(resource);
                ClassMetadata meta = reader.getClassMetadata();
                if (!meta.isInterface()) {
                    continue;
                }

                Class<?> type;
                try {
                    type = Class.forName(meta.getClassName());
                } catch (ClassNotFoundException e) {
                    log.warn(String.format("class %s not found", meta.getClassName()), e);
                    continue;
                }

                Object bean = getSkeleton("http://localhost:8080", type);

                String name = type.getSimpleName();
                name = name.substring(0, 1).toLowerCase() + name.substring(1);
                if (!factory.containsBean(name)) {
                    factory.registerSingleton(name, bean);
                }
            }
        } catch (IOException e) {
            log.error("list skeletons failed", e);
        }
    }
}
